﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Andwp.AudioPlayer
{
    /// <summary>
    /// Winmm的交互类。
    /// </summary>
    class WinmmInterop
    {
        /// <summary>
        /// 调用模块名称。
        /// </summary>
        private const string Winmm = "Winmm";

        #region WinAPI提供的常量
        /* flags for wFormatTag field of WAVEFORMAT */
        public const int WAVE_FORMAT_PCM = 1;
        public const int CALLBACK_FUNCTION = 0x00030000;
        public const int MMSYSERR_NOERROR = 0;                  /* no error */
        public const int MMSYSERR_BASE = 0;
        public const int MMSYSERR_ERROR = (MMSYSERR_BASE + 1);/* unspecified error */
        public const int MMSYSERR_BADDEVICEID = (MMSYSERR_BASE + 2);/* device ID out of range */
        public const int MMSYSERR_NOTENABLED = (MMSYSERR_BASE + 3);/* driver failed enable */
        public const int MMSYSERR_ALLOCATED = (MMSYSERR_BASE + 4);/* device already allocated */
        public const int MMSYSERR_INVALHANDLE = (MMSYSERR_BASE + 5);/* device handle is invalid */
        public const int MMSYSERR_NODRIVER = (MMSYSERR_BASE + 6);/* no device driver present */
        public const int MMSYSERR_NOMEM = (MMSYSERR_BASE + 7);/* memory allocation error */
        public const int MMSYSERR_NOTSUPPORTED = (MMSYSERR_BASE + 8);/* function isn't supported */
        public const int MMSYSERR_BADERRNUM = (MMSYSERR_BASE + 9);/* error value out of range */
        public const int MMSYSERR_INVALFLAG = (MMSYSERR_BASE + 10);/* invalid flag passed */
        public const int MMSYSERR_INVALPARAM = (MMSYSERR_BASE + 11);/* invalid parameter passed */
        public const int MMSYSERR_HANDLEBUSY = (MMSYSERR_BASE + 12);/* handle being used */
        /* simultaneously on another */
        /* thread (eg callback) */
        public const int MMSYSERR_INVALIDALIAS = (MMSYSERR_BASE + 13); /* specified alias not found */
        public const int MMSYSERR_BADDB = (MMSYSERR_BASE + 14); /* bad registry database */
        public const int MMSYSERR_KEYNOTFOUND = (MMSYSERR_BASE + 15); /* registry key not found */
        public const int MMSYSERR_READERROR = (MMSYSERR_BASE + 16); /* registry read error */
        public const int MMSYSERR_WRITEERROR = (MMSYSERR_BASE + 17); /* registry write error */
        public const int MMSYSERR_DELETEERROR = (MMSYSERR_BASE + 18); /* registry delete error */
        public const int MMSYSERR_VALNOTFOUND = (MMSYSERR_BASE + 19); /* registry value not found */
        public const int MMSYSERR_NODRIVERCB = (MMSYSERR_BASE + 20); /* driver does not call DriverCallback */
        public const int MMSYSERR_MOREDATA = (MMSYSERR_BASE + 21); /* more data to be returned */
        public const int MMSYSERR_LASTERROR = (MMSYSERR_BASE + 21); /* last error in range */
        public const int MM_WOM_DONE = 0x3BD;
        public const int WOM_DONE = MM_WOM_DONE;

        public const int MM_WOM_OPEN = 0x3BB;           /* waveform output */
        public const int MM_WOM_CLOSE = 0x3BC;

        public const int WOM_OPEN = MM_WOM_OPEN;
        public const int WOM_CLOSE = MM_WOM_CLOSE;
        #endregion

        /// <summary>
        /// 输出处理
        /// </summary>
        /// <param name="hWaveOut"></param>
        /// <param name="uMsg"></param>
        /// <param name="dwInstance"></param>
        /// <param name="dwParam1"></param>
        /// <param name="dwParam2"></param> 
        public delegate void WaveOutProc(IntPtr hWaveOut, uint uMsg, UIntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2);

        /// <summary>
        /// 波形参数
        /// </summary>
        public struct WAVEFORMATEX
        {
            public ushort wFormatTag;  /* format type */
            public ushort nChannels;   /* number of channels (i.e. mono, stereo...) */
            public uint nSamplesPerSec;    /* sample rate */
            public uint nAvgBytesPerSec;   /* for buffer estimation */
            public ushort nBlockAlign; /* block size of data */
            public ushort wBitsPerSample;  /* number of bits per sample of mono data */
            public ushort cbSize;  /* the count in bytes of the size of */
            /* extra information (after cbSize) */
        };

        /// <summary>
        /// 波形数据头
        /// </summary>
        public struct WAVEHDR
        {
            public IntPtr lpData;                 /* pointer to locked data buffer */
            public uint dwBufferLength;         /* length of data buffer */
            public uint dwBytesRecorded;        /* used for input only */
            public IntPtr dwUser;                 /* for client's use */
            public uint dwFlags;                /* assorted flags (see defines) */
            public uint dwLoops;                /* loop control counter */
            public IntPtr lpNext;   //wavehdr_tag *lpNext;     /* reserved for driver */
            public IntPtr reserved;               /* reserved for driver */
        };
     
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hwo"></param>
        /// <param name="pwh"></param>
        /// <param name="cbwh"></param>
        /// <returns></returns>
        [DllImport(Winmm, CallingConvention = CallingConvention.Winapi)]
        public unsafe extern static uint waveOutUnprepareHeader(IntPtr* hwo, WAVEHDR* pwh, uint cbwh);

        /// <summary>
        /// 波形输出打开
        /// </summary>
        /// <param name="phwo"></param>
        /// <param name="uDeviceID"></param>
        /// <param name="pwfx"></param>
        /// <param name="dwCallback"></param>
        /// <param name="dwInstance"></param>
        /// <param name="fdwOpen"></param>
        /// <returns></returns>
        [DllImport(Winmm, CallingConvention = CallingConvention.Winapi)]
        public unsafe extern static uint waveOutOpen(IntPtr* phwo, IntPtr uDeviceID, WAVEFORMATEX* pwfx, WaveOutProc dwCallback, UIntPtr dwInstance, uint fdwOpen);

        /// <summary>
        /// 数据准备标志
        /// </summary>
        /// <param name="phwo"></param>
        /// <param name="pwh"></param>
        /// <param name="cbwh"></param>
        /// <returns></returns>
        [DllImport(Winmm, CallingConvention = CallingConvention.Winapi)]
        public extern static uint waveOutPrepareHeader(IntPtr phwo, ref WAVEHDR pwh, uint cbwh);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hwo"></param>
        /// <param name="waveHead"></param>
        /// <param name="cbwh"></param>
        /// <returns></returns>
        [DllImport(Winmm, CallingConvention = CallingConvention.Winapi)]
        public extern static uint waveOutWrite(IntPtr hwo, IntPtr waveHead, uint cbwh);

        /// <summary>
        /// 重设
        /// </summary>
        /// <param name="hwo"></param>
        /// <returns></returns>
        [DllImport(Winmm, CallingConvention = CallingConvention.Winapi)]
        public extern static uint waveOutReset(IntPtr hwo);

        /// <summary>
        /// 关闭
        /// </summary>
        /// <param name="hwo"></param>
        /// <returns></returns>
        [DllImport(Winmm, CallingConvention = CallingConvention.Winapi)]
        public extern static uint waveOutClose(IntPtr hwo);

        /// <summary>
        /// 暂停
        /// </summary>
        /// <param name="hwo"></param>
        /// <returns></returns>
        [DllImport(Winmm, CallingConvention = CallingConvention.Winapi)]
        public extern static uint waveOutPause(IntPtr hwo);

        /// <summary>
        /// 设置设备音量
        /// </summary>
        /// <param name="hwo"></param>
        /// <param name="dwVolume"></param>
        /// <returns></returns>
        [DllImport(Winmm, CallingConvention = CallingConvention.Winapi)]
        public extern static uint waveOutSetVolume(IntPtr hwo, uint dwVolume);

        /// <summary>
        /// 获取设备音量
        /// </summary>
        /// <param name="hwo"></param>
        /// <param name="dwVolume"></param>
        /// <returns></returns>
        [DllImport(Winmm, CallingConvention = CallingConvention.Winapi)]
        public extern static uint waveOutGetVolume(IntPtr hwo, ref uint dwVolume);

        /// <summary>
        /// 获取当前播放设备个数。
        /// </summary>
        /// <returns></returns>
        [DllImport(Winmm)]
       public static extern uint waveOutGetNumDevs();

        /// <summary>
        /// 获取设备信息。
        /// </summary>
        /// <param name="uDeviceID"></param>
        /// <param name="pwoc"></param>
        /// <param name="cbwoc"></param>
        /// <returns></returns>
        [DllImport(Winmm, CharSet = CharSet.Unicode)]
        public static extern uint waveOutGetDevCaps(UIntPtr uDeviceID, ref WAVEOUTCAPS pwoc, uint cbwoc);

        /// <summary>
        /// 输出设备能力描述。
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
       public struct WAVEOUTCAPS
        {
            /// <summary>
            /// 厂商ID。
            /// </summary>
            public ushort wMid;

            /// <summary>
            /// 产品ID。
            /// </summary>
            public ushort wPid;

            /// <summary>
            /// 驱动版本号。
            /// </summary>
            public uint vDriverVersion;

            /// <summary>
            /// 产品名称。
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2 * 32)]
            public byte[] szPname;

            /// <summary>
            /// 支持标准。
            /// </summary>
            public uint dwFormats;

            /// <summary>
            /// 支持通道。
            /// supports mono (1) or stereo (2)。
            /// </summary>
            public ushort wChannels;

            /// <summary>
            /// 保留。
            /// </summary>
            public ushort wReserved1;

            /// <summary>
            /// 
            /// </summary>
            public uint dwSupport;
        }
    }
}
